package com.oss.service.oss;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.oss.dto.oss.capitalmanage.CapitalManageImportDetailDto;
import com.oss.dto.oss.capitalmanage.CapitalManageImportDto;
import com.oss.dto.oss.capitalsummary.CapitalSummaryImportDetailDto;
import com.oss.dto.oss.capitalsummary.CapitalSummaryImportDto;
import com.oss.dto.oss.positionmanage.ImportDetailDto;
import com.oss.dto.oss.positionmanage.ImportDto;
import com.oss.dto.oss.trademanage.TradeManageImportDetailDto;
import com.oss.dto.oss.trademanage.TradeManageImportDto;
import com.oss.entity.oss.Student;
import com.oss.util.easyexcel.EasyExcelDataListenerNoHeader;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;

@Slf4j
@Service
public class DataImportService {
    @Autowired
    CapitalSummaryService capitalSummaryService;
    @Autowired
    CapitalManageService capitalManageService;
    @Autowired
    PositionManageService positionManageService;
    @Autowired
    TradeManageService tradeManageService;
    @Autowired
    StudentService studentService;

    public void importTradeInfo(MultipartFile file,String account) throws Exception {
        importTradeInfo(file.getInputStream(),account);
    }
    public void importTradeInfo(InputStream inputStream,String account) throws Exception {
        ExcelReader reader = EasyExcel.read(inputStream).build();
        EasyExcelDataListenerNoHeader settlementListener = new EasyExcelDataListenerNoHeader();
        List<ReadSheet> readSheetList = new ArrayList<>();
        ReadSheet settlementSheet = EasyExcel.readSheet("客户交易结算日报").registerReadListener(settlementListener).headRowNumber(0).build();
        readSheetList.add(settlementSheet);
        EasyExcelDataListenerNoHeader tradeListener = new EasyExcelDataListenerNoHeader();
        ReadSheet tradeSheet = EasyExcel.readSheet("期权成交明细").registerReadListener(tradeListener).headRowNumber(0).build();
        readSheetList.add(tradeSheet);
        reader.read(readSheetList);
        reader.finish();
        // 客户交易结算日报sheet页面数据
        List<Map<Integer,String>> settlementDataList = settlementListener.getDataList();

        // 交易日期
        LocalDate tradeDate = null;
        Student student = null;
        for (int index=0;index<settlementDataList.size();index++){
            Map<Integer,String> item = settlementDataList.get(index);
            String value = item.get(0);
            if (StringUtils.isNotBlank(value) && "基本资料".equals(value)) {
                // 取下一行
                Map<Integer,String> accountItem = settlementDataList.get(index+1);
                // 第一列=客户期货期权内部资金账户
                if (StringUtils.isNotBlank(value) && "客户期货期权内部资金账户".equals(accountItem.get(0))) {
                    student = studentService.getByAccount(account);
                    if (student == null) {
                        throw new RuntimeException("导入场内数据时 , 根据账户查询不到对应学员 , 账号="+account);
                    }
                    tradeDate = LocalDate.parse(accountItem.get(7));
                }
            }
        }
        doSettlementDataList(settlementDataList,tradeDate,student);
        // 期权成交明细sheet页面数据
        List<Map<Integer,String>> tradeDataList = tradeListener.getDataList();
        doTradeInfoData(tradeDataList,student);
        log.info("settlementDataList="+settlementDataList.size());
    }

    /**
     * 处理 期权成交明细  sheet页数据
     * @param tradeDataList
     */
    private void doTradeInfoData(List<Map<Integer, String>> tradeDataList,Student student) {
        TradeManageImportDto dto = new TradeManageImportDto();
        List<TradeManageImportDetailDto> list = new ArrayList<>();
        boolean readStart = false;
        for (int index=0;index<tradeDataList.size();index++){
            Map<Integer,String> item = tradeDataList.get(index);
            // 已经找到数据区域 , 后面行都是数据行
            if (readStart == true) {
                 if ("合计".equals(item.get(0))) {
                    break;
                }
                TradeManageImportDetailDto vo = new TradeManageImportDetailDto();
                vo.setAccount(student.getAccount());
                vo.setInstrumentCode(item.get(0));
                vo.setSerialNumber(Integer.parseInt(item.get(1)));
                vo.setTradeTime(LocalTime.parse(item.get(2)));
                if ("买".equals(item.get(3))) {
                    vo.setOffsetFlag("Buy");
                } else if ("卖".equals(item.get(3))) {
                    vo.setOffsetFlag("Sell");
                }
                vo.setTradeSinglePrice(getBigDecimal(item.get(4)));
                vo.setTradeVolume(getBigDecimal(item.get(5)));
                vo.setPremium(getBigDecimal(item.get(6)));
                vo.setTaxFlag("否".equals(item.get(7)) ? 0 : 1);
                vo.setCommission(getBigDecimal(item.get(8)));
                vo.setTradeDate(LocalDate.parse(item.get(9)));
                vo.setDataSource(0);
                list.add(vo);
            } else {
                String value = item.get(0);
                // 期权成交明细
                if (StringUtils.isNotBlank(value) && "期权成交明细".equals(value)) {
                    readStart = true;
                    // index往下跳1行 , 因为有表头
                    index = index+1;
                }
            }
        }
        if (CollectionUtils.isNotEmpty(list)) {
            dto.setList(list);
            tradeManageService.importData(dto);
        }
    }

    /**
     * 处理  客户交易结算日报  sheet页数据
     * @param settlementDataList
     */
    public void doSettlementDataList(List<Map<Integer,String>> settlementDataList,LocalDate tradeDate,Student student){

        for (int index=0;index<settlementDataList.size();index++){
            Map<Integer,String> item = settlementDataList.get(index);
            String value = item.get(0);
            // 从此行开始 , 往后读取9行
            if (StringUtils.isNotBlank(value) && "期货期权账户资金状况".equals(value)) {
                doAccountCapitalStatus(student,settlementDataList,index+1,index+9,tradeDate);
                break;
            }
        }
        Integer inoutStartIndex = null;
        for (int index=0;index<settlementDataList.size();index++){
            Map<Integer,String> item = settlementDataList.get(index);
            String value = item.get(0);
            Integer endIndex = null;
            if (StringUtils.isNotBlank(value) && "期货期权账户出入金明细（单位：人民币）".equals(value)) {
                inoutStartIndex = index;
            } else if (StringUtils.isNotBlank(value) && "合计".equals(value) && inoutStartIndex != null) {
                endIndex = index;
                if (inoutStartIndex != null) {
                    doInOutCapitalDetail(student,settlementDataList,inoutStartIndex+2,endIndex-1,tradeDate);
                    break;
                }

            }
        }
        Integer startIndex = null;
        for (int index=0;index<settlementDataList.size();index++){
            Map<Integer,String> item = settlementDataList.get(index);
            String value = item.get(0);
            Integer endIndex = null;
            if (StringUtils.isNotBlank(value) && "期权持仓汇总".equals(value)) {
                startIndex = index;
            } else if (StringUtils.isNotBlank(value) && "合计".equals(value)  && startIndex!= null) {
                endIndex = index;
                if (startIndex != null) {
                    doPositionCount(student,settlementDataList,startIndex+2,endIndex-1,tradeDate);
                    break;
                }
            }
        }

    }

    /**
     * 处理  期货期权账户资金状况  区域数据
     * @param settlementDataList  sheet全部数据
     * @param startIndex          期货期权账户资金状况区域数据开始行下标(包含)
     * @param endIndex            期货期权账户资金状况区域数据结束行下标(包含)
     */
    public void doAccountCapitalStatus(Student student,List<Map<Integer,String>> settlementDataList , int startIndex , int endIndex, LocalDate tradeDate){
        Map<String,String> map = new LinkedHashMap<>();
        for (int index=startIndex;index<settlementDataList.size() && index <= endIndex;index++){
            Map<Integer,String> item = settlementDataList.get(index);
            log.info("doAccountCapitalStatus index="+index+" 行信息= " + JSON.toJSONString(item));
            map.put(item.get(0),item.get(2).replace(",",""));
            map.put(item.get(5),item.get(7).replace(",",""));
        }
        CapitalSummaryImportDetailDto dto = new CapitalSummaryImportDetailDto();
        dto.setAccount(student.getAccount());
        dto.setOccurrenceDate(tradeDate);
        dto.setPreviousDayBalance(new BigDecimal(map.get("上日结存")));
        dto.setDailyTotalDepositAndWithdrawal(new BigDecimal(map.get("当日存取合计")));
        dto.setProfitLoss(new BigDecimal(map.get("平仓盈亏")));
        dto.setDailyTotalPremium(new BigDecimal(map.get("当日总权利金")));
        dto.setDailyTotalCommission(new BigDecimal(map.get("当日手续费")));
        dto.setDailyDayBalance(new BigDecimal(map.get("当日结存")));
        dto.setFloatingProfitLoss(new BigDecimal(map.get("浮动盈亏")));

        dto.setClientEquity(new BigDecimal(map.get("客户权益")));
        dto.setActualMonetaryFunds(new BigDecimal(map.get("实有货币资金")));
        dto.setNonCashMarginValue(new BigDecimal(map.get("非货币充抵金额")));
        dto.setCashMarginValue(new BigDecimal(map.get("货币充抵金额")));
        dto.setFrozenFunds(new BigDecimal(map.get("冻结资金")));
        dto.setMarginOccupy(new BigDecimal(map.get("保证金占用")));
        dto.setAvailableAmount(new BigDecimal(map.get("可用资金")));
        dto.setRiskExposure(map.get("风险度"));
        dto.setAppendMargin(new BigDecimal(map.get("追加保证金")));
        dto.setDataSource(0);
        CapitalSummaryImportDto capitalSummaryImportDto = new CapitalSummaryImportDto();
        capitalSummaryImportDto.setList(Arrays.asList(dto));
        capitalSummaryService.importData(capitalSummaryImportDto);
    }
    /**
     * 处理  期货期权账户出入金明细（单位：人民币）  区域数据
     * @param student             学员
     * @param settlementDataList  sheet全部数据
     * @param startIndex          出入金数据开始行下标(包含)
     * @param endIndex            出入金数据结束行下标(包含)
     */
    public void doInOutCapitalDetail(Student student,List<Map<Integer,String>> settlementDataList , int startIndex , int endIndex,LocalDate tradeDate){
        CapitalManageImportDto dto = new CapitalManageImportDto();
        List<CapitalManageImportDetailDto> list = new ArrayList<>();
        for (int index=startIndex;index<settlementDataList.size() && index <= endIndex;index++){
            Map<Integer,String> item = settlementDataList.get(index);
            CapitalManageImportDetailDto vo = new CapitalManageImportDetailDto();
            vo.setAccount(student.getAccount());
            vo.setTradeDate(LocalDate.parse(item.get(0))); // 发生日期
            String inCapital = item.get(2).replace(",","");
            String outCapital = item.get(4).replace(",","");
            if (StringUtils.isNotBlank(inCapital) || getBigDecimal(inCapital) != BigDecimal.ZERO) {
                vo.setInoutFlag(1);
                vo.setAmount(getBigDecimal(inCapital));
            }
            if (StringUtils.isNotBlank(outCapital) || getBigDecimal(outCapital) != BigDecimal.ZERO) {
                vo.setInoutFlag(0);
                vo.setAmount(getBigDecimal(outCapital));
            }
            // 出入金表格中摘要列 , 赋值给remark , 方式列写死出入金
            vo.setRemark(item.get(8));
            vo.setDataSource(0);
            list.add(vo);
        }
        if (CollectionUtils.isNotEmpty(list)) {
            dto.setList(list);
            capitalManageService.importData(dto);
        }
    }
    /**
     * 处理  期权持仓汇总  区域数据
     * @param student             学原
     * @param settlementDataList  sheet全部数据
     * @param startIndex          期权持仓汇总数据开始行下标(包含)
     * @param endIndex            期权持仓汇总数据结束行下标(包含)
     */
    public void doPositionCount(Student student,List<Map<Integer,String>> settlementDataList , int startIndex , int endIndex,LocalDate tradeDate){
        ImportDto dto = new ImportDto();
        List<ImportDetailDto> list = new ArrayList<>();
        for (int index=startIndex;index<settlementDataList.size() && index <= endIndex;index++){
            Map<Integer,String> item = settlementDataList.get(index);
            ImportDetailDto vo = new ImportDetailDto();
            vo.setAccount(student.getAccount());
            vo.setInstrumentCode(item.get(0));
            vo.setVarietyCode(item.get(1));
            if ("看涨期权".equals(item.get(2))) {
                vo.setOptionType("CallOption");
            } else if ("看跌期权".equals(item.get(2))) {
                vo.setOptionType("PutOption");
            }
            vo.setStrikePrice(getBigDecimal(item.get(3)));
            vo.setBuyPosition(getBigDecimal(item.get(4)));
            vo.setBuyAveragePrice(getBigDecimal(item.get(5)));
            vo.setSellPosition(getBigDecimal(item.get(6)));
            vo.setSellAveragePrice(getBigDecimal(item.get(7)));
            vo.setYesterdaySettlementPrice(getBigDecimal(item.get(8)));
            vo.setTodaySettlementPrice(getBigDecimal(item.get(9)));
            vo.setTradeMargin(getBigDecimal(item.get(10)));
            vo.setTradeCode(item.get(11));
            vo.setPositionDate(tradeDate);
            vo.setDataSource(0);
            list.add(vo);
        }
        if (CollectionUtils.isNotEmpty(list)) {
            dto.setList(list);
            positionManageService.importData(dto);
        }
    }

    public BigDecimal getBigDecimal(String str){
        if (StringUtils.isBlank(str)) {
            return BigDecimal.ZERO;
        } else {
            str = str.replace(",","");
            if (StringUtils.isBlank(str)) {
                return BigDecimal.ZERO;
            } else {
                return new BigDecimal(str);
            }
        }
    }
}